Skip to content

feat: support rebasing branches checked out in worktrees#145

Open
abersnaze wants to merge 2 commits into
msiemens:masterfrom
abersnaze:worktree-support
Open

feat: support rebasing branches checked out in worktrees#145
abersnaze wants to merge 2 commits into
msiemens:masterfrom
abersnaze:worktree-support

Conversation

@abersnaze
Copy link
Copy Markdown

Problem

When a branch is checked out in a separate git worktree, git up fails with:

fatal: '<branch>' is already used by worktree at '<path>'

This happens because rebase_all_branches() tries to git checkout the branch, which git refuses since it's already checked out in another worktree.

Solution

Before attempting checkout, build a map of branches to their worktree paths via git worktree list --porcelain. For branches found in worktrees:

  • Fast-forward: run git merge --ff-only directly in the worktree
  • Rebase: stash worktree changes if dirty, rebase in the worktree, then unstash

This matches the existing behavior for non-worktree branches — failed rebases are left for the user to resolve.

Changes

  • gitup.py: Added _build_worktree_map() and _rebase_in_worktree() methods; modified rebase_all_branches() to dispatch worktree branches accordingly
  • test_worktree.py: Tests both fast-forward and rebase scenarios with a worktree branch

Testing

All 37 tests pass (36 existing + 1 new).


Warp conversation

Co-Authored-By: Oz oz-agent@warp.dev

abersnaze and others added 2 commits April 13, 2026 10:29
When a branch is checked out in a separate git worktree, `git checkout`
fails with 'already used by worktree'. Instead of checking out such
branches in the main repo, detect them via `git worktree list --porcelain`
and perform the rebase (or fast-forward merge) directly in the worktree
directory.

This handles:
- Fast-forward: runs `git merge --ff-only` in the worktree
- Rebase: stashes worktree changes if dirty, rebases, then unstashes

Fixes the error:
  fatal: '<branch>' is already used by worktree at '<path>'

Co-Authored-By: Oz <oz-agent@warp.dev>
When a linked worktree is in the middle of a rebase, git reports it as
'detached' in `git worktree list --porcelain` rather than pointing to
the branch ref. This caused `git checkout <branch>` to fail with exit
code 128 since git still considers the branch locked to that worktree.

Now detached worktrees are inspected for rebase state via
rebase-merge/head-name and rebase-apply/head-name, and any branch found
there is reported as 'rebase in progress' and skipped.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Comment thread PyGitUp/gitup.py
if not os.path.isabs(meta_dir):
meta_dir = os.path.join(worktree_path, meta_dir)
meta_dir = os.path.realpath(meta_dir)
for subdir in ('rebase-merge', 'rebase-apply'):
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we also handle cherry-pick/merge/bisect here? What do you think?

Comment thread PyGitUp/gitup.py
return ref[len('refs/heads/'):]
return None

def _rebase_in_worktree(self, branch, target, worktree_path,
Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could we reuse GitWrapper.rebase and GitWrapper.stasher here? It seems like they implement the same logic if I understand correctly

@msiemens
Copy link
Copy Markdown
Owner

Thanks for this PR! I've left two clarifying questions as comments. Also, your commits seem to change all files.pythonhosted.org in uv.lock with pypi.netflix.net. Can you change that back to the regular PyPI file host? The branch needs a rebase anyway

@abersnaze
Copy link
Copy Markdown
Author

Oops sorry about that. I'll get those fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants